<?php

namespace app\services;

use app\payment\PayFactory;
use app\traits\Page;
use plugin\admin\app\model\Exchange;
use plugin\admin\app\model\ExchangeApply;
use plugin\admin\app\model\ExchangeCategory;
use plugin\admin\app\model\VideoComment;
use plugin\admin\app\model\ExchangeImage;
use plugin\admin\app\model\ExchangeReport;
use plugin\admin\app\model\ExpressCompany;
use plugin\admin\app\model\Like;
use plugin\admin\app\model\Option;
use plugin\admin\app\model\Order;
use plugin\admin\app\model\OrderReservation;
use plugin\admin\app\model\User;
use plugin\admin\app\model\UserAddress;
use plugin\admin\app\model\UserChat;
use plugin\admin\app\model\UserChatMessage;
use plugin\admin\app\model\UserCollect;
use plugin\admin\app\model\UserExchange;
use plugin\admin\app\model\UserFollowing;
use plugin\admin\app\model\UserHistory;
use plugin\admin\app\model\UserProperty;
use plugin\admin\app\model\UserPropertyLog;
use plugin\admin\app\model\UserSearchHistory;
use support\Db;

class ExchangeService
{
    use Page;

    public static function add($data)
    {
        $category = ExchangeCategory::find($data['category_id']);

        if (!$category) {
            throw new \Exception('不存在的分类');
        }

        if (is_string($data['thumbs'])) {
            $thumbs = [$data['thumbs']];
        } else {
            $thumbs = $data['thumbs'];
        }

        $data['user_id'] = get_user_id();
        $data['status'] = Exchange::STATUS_WAIT_EXCHANGE;
        $data['is_up'] = 1;
        $data['created_time'] = date('Y-m-d H:i:s');
        $data['thumbs'] = json_encode($thumbs, JSON_UNESCAPED_UNICODE);

        return Exchange::insertGetId($data);
    }

    public static function show($id)
    {
        $exchangeInfo = Exchange::where('id', $id)->where('user_id', get_user_id())->first();

        if (!$exchangeInfo) {
            throw new \Exception('不存在的换物');
        }

        return $exchangeInfo;
    }

    public static function edit($id, $data)
    {
        $exchangeInfo = Exchange::where('id', $id)->where('user_id', get_user_id())->first();

        if (!$exchangeInfo) {
            throw new \Exception('不存在的换物');
        }

        $category = ExchangeCategory::find($data['category_id']);

        if (!$category) {
            throw new \Exception('不存在的分类');
        }

        if (is_string($data['thumbs'])) {
            $thumbs = [$data['thumbs']];
        } else {
            $thumbs = $data['thumbs'];
        }

        $data['user_id'] = get_user_id();
        $data['status'] = Exchange::STATUS_WAIT_EXCHANGE;
        $data['is_up'] = 1;
        $data['created_time'] = date('Y-m-d H:i:s');
        $data['thumbs'] = json_encode($thumbs, JSON_UNESCAPED_UNICODE);

        Exchange::where('id', $id)->update($data);
    }

    public static function userList($page, $length = 10, $keyword = '')
    {
        $offset = ($page - 1) * $length;

        $query = User::select(['id', 'nickname', 'avatar', 'exchange_count']);

        if (!empty($keyword)) {
            $query = $query->where('nickname', 'like', "%{$keyword}%");
        }

        $totalCount = (clone $query)->count();
        $list = $query->select(['id', 'nickname', 'avatar', 'exchange_count'])->offset($offset)->limit($length)->orderByDesc('exchange_count')->get()->toArray();

        return Page::wrap($totalCount, $page, $length, $list);
    }

    public static function list($page, $length = 10, $categoryId = 0, $keyword = '', $order = ['created_time', 'desc'])
    {
        $offset = ($page - 1) * $length;

        $query = Exchange::select(['id', 'user_id', 'name', 'wants_count', 'thumbs'])->where('status', 1)->where('is_temp', 0)->where('is_up', 1)->whereNull('delete_time');

        if ($categoryId > 0) {
            $query = $query->where('category_id', $categoryId);
        }

        if (!empty($keyword)) {
            $query = $query->where('name', 'like', "%{$keyword}%");

            KeywordService::add($keyword);
        }

        $totalCount = (clone $query)->count();

        if (count($order) > 0) {
            $exchanges = $query->orderBy($order[0], $order[1])->offset($offset)->limit($length)->get()->toArray();
        }

        $userIds = array_column($exchanges, 'user_id');

        $users = User::select(['id', 'nickname', 'avatar'])->whereIn('id', $userIds)->get()->toArray();
        $users = array_combine(
            array_column($users, 'id'),
            array_values($users)
        );

        foreach ($exchanges as $key=>$exchange) {
            $exchange['thumbs'] = json_decode($exchange['thumbs'], true);
            $exchanges[$key] = $exchange;
            $exchanges[$key]['userInfo'] = $users[$exchange['user_id']];
        }

        return Page::wrap($totalCount, $page, $length, $exchanges);
    }

    public static function finish($id)
    {
        $exchangeInfo = Exchange::where('id', $id)->where('user_id', get_user_id())->first();

        if (!$exchangeInfo) {
            throw new \Exception('不存在的换物');
        }

        $exchangeInfo->status = Exchange::STATUS_FINISH_EXCHANGE;
        $exchangeInfo->save();
    }

    public static function delete($id)
    {
        $exchangeInfo = Exchange::where('id', $id)->where('user_id', get_user_id())->first();

        if (!$exchangeInfo) {
            throw new \Exception('不存在的换物');
        }

        $exchangeInfo->delete();

        ExchangeImage::where('exchange_id', $id)->delete();
    }

    public static function detail($id)
    {
        $query = Exchange::select(['id', 'name', 'desc', 'quality', 'wants_count', 'views_count', 'like_count', 'collect_count', 'status', 'user_id', 'exchange_name', 'exchange_desc', 'exchange_quality', 'comment_count', 'thumbs', 'is_up', 'created_time', 'poster'])->where('id', $id)->where('is_up', 1)->where('is_temp', 0);

        $exchange = $query->first();

        if (!$exchange) {
            throw new \Exception('不存在的换物');
        }

        $exchange = $exchange->toArray();

        $exchange['thumbs'] = json_decode($exchange['thumbs'], true);
        $exchange['user_info'] = User::select(['id', 'nickname', 'avatar'])->where('id', $exchange['user_id'])->first();
        $exchange['time_text'] = diff_time($exchange['created_time']);
        $exchange['status_text'] = Exchange::getStatusText($exchange);
        $exchange['is_following'] = FollowingService::isFollowing($exchange['user_id']);
        $exchange['is_like'] = LikeService::isLike($exchange['id'], Like::TYPE_EXCHANGE);
        $exchange['is_collect'] = UserCollectService::hasCollect(UserCollect::EXCHANGE, $exchange['id']);

        if (get_user_id() != $exchange['user_id']) {
            UserHistoryService::add(UserHistory::EXCHANGE, $id);
        }

        $applyInfo = ExchangeApply::where('exchange_id', $id)->where('user_id', get_user_id())->first();

        $exchange['apply_status']  = 0;
        if (isset($applyInfo)) {
            $exchange['apply_status'] = 1;

            if ($applyInfo['reject_time']) {
                $exchange['apply_status'] = 2;
            }

            if ($applyInfo['agree_time']) {
                $exchange['apply_status'] = 3;
            }
        }

        return $exchange;
    }

    public static function comments($page, $length = 10)
    {
        $offset = ($page - 1) * $length;
        $userId = get_user_id();
        $exchanges = Exchange::select(['id', 'thumbs'])->where('user_id', $userId)->get()->toArray();
        $exchangeIds = array_column($exchanges, 'id');

        $query = VideoComment::select(['exchange_id', 'reply_user_id', 'user_id', 'content', 'created_time'])->where([
            ['exchange_id', 'in', $exchangeIds],
            ['reply_user_id', '=', 0]
        ])->orWhere('reply_user_id', '=', $userId);

        $totalCount = (clone $query)->count();
        $list = $query->offset($offset)->limit($length)->orderByDesc('created_time')->get()->toArray();

        $exchangeIds = array_column($list, 'exchange_id');
        $exchanges = Exchange::select(['id', 'thumbs'])->whereIn('id', $exchangeIds)->get()->toArray();
        $exchanges = array_combine(
            array_column($exchanges, 'id'),
            array_values($exchanges)
        );

        $userIds = array_column($list, 'user_id');
        $users = User::select(['id', 'nickname', 'avatar'])->whereIn('id', $userIds)->get()->toArray();
        $users = array_combine(
            array_column($users, 'id'),
            array_values($users)
        );

        foreach ($list as $key=>$comment) {
            if ($comment['reply_user_id'] == 0) {
                $list[$key]['reply_type'] = 1;
            } else {
                $list[$key]['reply_type'] = 2;
            }
            $list[$key]['exchange_info'] = $exchanges[$comment['exchange_id']];
            $list[$key]['user_info'] = $users[$comment['user_id']];
        }

        return Page::wrap($totalCount, $page, $length, $list);
    }

    public static function paySuccess($userId, $orderNo)
    {

        if ($orderNo) {
            $order = Order::where('order_no', $orderNo)->first();


            $order['pay_time'] = date('Y-m-d H:i:s');
            $order['status'] = Order::STATUS_FINISH;
            $order->save();

            UserExchange::insert([
                'user_id' => $userId,
                'exchange_id' => $order['remark'],
                'created_time' => date('Y-m-d H:i:s')
            ]);
        }

    }

    public static function applyList($page, $length, $status = 0, $keyword = '')
    {
        $offset = ($page - 1) * $length;

        $query = Db::table('wa_exchange_apply', 'ea')
            ->select(['ea.id', 'ea.status', 'ea.created_time', 'e.name', 'e.thumbs', 'e.quality', 'u.nickname', 'u.avatar'])
            ->join(Db::raw('wa_exchanges as e'), 'ea.exchange_id', '=', 'e.id', 'left')
            ->join(Db::raw('wa_users as u'), 'e.user_id', '=', 'u.id', 'left')
            ->where('ea.user_id', get_user_id());

        if ($status >= 0) {
            $query = $query->where('ea.status', $status);
        }

        if ($keyword) {
            $query = $query->where('e.name', 'like', "%{$keyword}%");
        }

        $totalCount = (clone $query)->count();
        $exchanges = $query->orderByDesc('created_time')->offset($offset)->limit($length)->get()->toArray();

        foreach ($exchanges as $key=>$exchange) {
            $exchange = json_decode(json_encode($exchange), true);
            $exchange['thumbs'] = json_decode($exchange['thumbs'], true);
            $exchange['status_text'] = ExchangeApply::getStatusText($exchange['status']);
            $exchanges[$key] = $exchange;
        }

        return Page::wrap($totalCount, $page, $length, $exchanges);
    }

    public static function applyDetail($id)
    {
        $applyInfo = ExchangeApply::where('id', $id)->where('user_id', get_user_id())->first();

        if (!$applyInfo) {
            throw new \Exception('不存在的申请');
        }

        $query = Exchange::select(['id', 'name', 'desc', 'quality', 'wants_count', 'views_count', 'like_count', 'collect_count', 'status', 'user_id', 'exchange_name', 'exchange_desc', 'exchange_quality', 'comment_count', 'created_time'])->where('id', $applyInfo['exchange_id']);

        $exchange = $query->first();

        if (!$exchange) {
            throw new \Exception('不存在的换物');
        }

        $exchange = $exchange->toArray();

        $images = ExchangeImage::select('img_url')->where('exchange_id', $exchange['id'])->get()->toArray();

        $exchange['thumbs'] = array_column($images, 'img_url');
        $exchange['user_info'] = User::select(['id', 'nickname', 'avatar'])->where('id', $exchange['user_id'])->first();

        $applyInfo['exchange_info'] = $exchange;
        $applyInfo['status_text'] = ExchangeApply::getStatusText($applyInfo['status']);
        $applyInfo['address_info'] = json_decode($applyInfo['address_info'], true);
        $applyInfo['thumbs'] = json_decode($applyInfo['thumbs'], true);

        return $applyInfo;
    }

    public static function applyCancel($id)
    {
        $applyInfo = ExchangeApply::where('id', $id)->where('user_id', get_user_id())->first();

        if (!$applyInfo) {
            throw new \Exception('不存在的申请');
        }

        if ($applyInfo['status'] != ExchangeApply::STATUS_UN_PROCESS) {
            throw new \Exception('该状态不允许取消');
        }

        $applyInfo->status = ExchangeApply::STATUS_CANCEL;
        $applyInfo->save();

        Exchange::where('id', $applyInfo['exchange_id'])->decrement('wants_count', 1);
    }

    public static function applyExchange($exchangeId, $data, $addressId)
    {
        $exchangeInfo = Exchange::where('id', $exchangeId)->first();

        if (!$exchangeInfo || $exchangeInfo['is_temp'] || !$exchangeInfo['is_up'] || $exchangeInfo['delete_time']) {  //草稿，下架或已删除换物
            throw new \Exception('不存在的换物');
        }

        if ($exchangeInfo['user_id'] == get_user_id()) {
            throw new \Exception('无法与自己交易');
        }

        if ($exchangeInfo['status'] == Exchange::STATUS_FINISH_EXCHANGE) {
            throw new \Exception('该换物已置换');
        }

        $addressInfo = UserAddress::where('id', $addressId)->where('user_id', get_user_id())->first();

        if (!$addressInfo) {
            throw new \Exception('不存在的地址');
        }

        if ($applyInfo = ExchangeApply::where('user_id', get_user_id())->where('exchange_id', $exchangeId)->first()) {
//            if (!is_null($applyInfo['reject_time'])) {
//                throw new \Exception('卖家已拒绝');
//            }

            if ($applyInfo['status'] == 0) {
                throw new \Exception('已发起换货申请等待卖家通过');
            }
        }

        $applyId = ExchangeApply::insertGetId([
            'user_id' => get_user_id(),
            'exchange_id' => $exchangeId,
            'name' => $data['name'],
            'desc' => $data['desc'],
            'quality' => $data['quality'],
            'thumbs' => json_encode($data['thumbs'], JSON_UNESCAPED_UNICODE),
            'address_info' => json_encode($addressInfo),
            'status' => ExchangeApply::STATUS_UN_PROCESS,
            'created_time' => date('Y-m-d H:i:s')
        ]);

        Exchange::where('id', $exchangeId)->increment('wants_count', 1);

        if (!$chatInfo = ChatService::hasChat(get_user_id(), $exchangeInfo['user_id'])) {
            $chatId = ChatService::newChat($exchangeId);
            $chatInfo = UserChat::find($chatId);
        }

        ChatService::addMessage($chatInfo['id'], UserChatMessage::TYPE_APPLY_INFO, $applyId);
    }

    public static function report($exchangeId, $data)
    {
        $exchangeInfo = Exchange::where('id', $exchangeId)->first();

        if ($exchangeInfo['is_temp'] || !$exchangeInfo['is_up'] || $exchangeInfo['delete_time']) {  //草稿，下架或已删除换物
            throw new \Exception('不存在的换物');
        }

        if (ExchangeReport::where('user_id', get_user_id())->where('exchange_id', $exchangeId)->count() > 0) {
            throw new \Exception('你已举报过了，无需重复举报');
        }

        ExchangeReport::insert([
            'user_id' => get_user_id(),
            'exchange_id' => $exchangeId,
            'content' => $data['content'],
            'type_text' => $data['type_text'],
            'thumbs' => json_encode($data['thumbs'], JSON_UNESCAPED_UNICODE),
            'created_time' => date('Y-m-d H:i:s')
        ]);
    }

    public static function confirmReservation($orderNo, $expressId, $date, $timeRange, $addressId)
    {
        $orderInfo = Order::where('order_no', $orderNo)->first();

        if ($orderInfo['status'] == Order::STATUS_CANCEL) {
            throw new \Exception('订单已取消');
        }

        if (OrderReservation::where('order_no', $orderNo)->count() > 0) {
            throw new \Exception('你已预约');
        }

        $expressInfo = ExpressCompany::find($expressId);

        if (!$expressInfo) {
            throw new \Exception('不存在的物流公司');
        }

        $addressInfo = UserAddress::where('user_id', get_user_id())->where('id', $addressId)->get()->toArray();

        if (!$addressInfo) {
            throw new \Exception('不存在的地址');
        }

        OrderReservation::insert([
            'user_id' => get_user_id(),
            'order_no' => $orderNo,
            'express_info' => json_encode($expressInfo, true),
            'reservation_date' => $date,
            'reservation_time' => $timeRange,
            'address_info' => json_encode($addressInfo, true),
            'created_time' => date('Y-m-d H:i:s')
        ]);
    }

    public static function timeList()
    {
        $item = Option::where('name', "dict_reservation_time")->first();
        $values = json_decode($item['value'], true);
        $times = array_column($values, 'value');

        return $times;
    }

    public static function getCategories($pid = 0)
    {
        return ExchangeCategory::select(['id', 'name', 'thumb', 'sort'])->where('pid', $pid)->orderBy('sort')->get()->toArray();
    }

    public static function getAllCategories()
    {
        return ExchangeCategory::getTree();
    }

    public static function indexCategories()
    {
        $data = ExchangeCategory::select(['id', 'name', 'thumb', 'sort'])->where('is_index', 1)->orderBy('sort')->get()->toArray();

        foreach ($data as $key=>$value) {
            $value['thumb'] = full_url($value['thumb']);
            $data[$key] = $value;
        }

        return $data;
    }

    public static function deployUserAvatars($type = 'exchange')
    {
        if ($type == 'exchange') {
            $exchanges = Exchange::select(['user_id'])->where('status', 1)->where('is_temp', 0)->where('is_up', 1)->whereNull('delete_time')->get()->toArray();

            $userIds = array_column($exchanges, 'user_id');

            return User::select(['avatar'])->whereIn('id', $userIds)->get()->toArray();
        }
    }

    public static function guessYouLikeList($page, $length = 10)
    {
        $query = Exchange::select(['id', 'user_id', 'name', 'wants_count', 'thumbs'])->where('is_temp', 0)->where('is_up', 1)->where('status', 1)->whereNull('delete_time');

        $applies = ExchangeApply::where('buyer_user_id', get_user_id())->get()->toArray();
        $exchangeIds = array_column($applies, 'exchange_id');

        if (count($exchangeIds) > 0) {
            $exchanges = Exchange::whereIn('id', $exchangeIds)->get()->toArray();
            $categoryIds = array_column($exchanges, 'category_id');

            $query = $query->whereIn('category_id', $categoryIds);
        }

        $offset = ($page - 1) * $length;

        $totalCount = (clone $query)->count();
        $list = $query->offset($offset)->limit($length)->orderBy('wants_count', 'desc')->get()->toArray();

        $userIds = array_column($list, 'user_id');
        $users = User::select(['id', 'nickname', 'avatar'])->whereIn('id', $userIds)->get()->toArray();
        $users = array_combine(
            array_column($users, 'id'),
            array_values($users)
        );

        foreach ($list as $key=>$value) {
            $list[$key]['user_info'] = $users[$value['user_id']] ?? [];
            $list[$key]['thumbs'] = json_decode($value['thumbs'], true);
        }

        return Page::wrap($totalCount, $page, $length, $list);
    }

    public static function guessYouLikeCategories($pid = 0, $categories = [])
    {
        if (!get_user_id()) {
            return [];
        }

        if (empty($categories)) {
            $categories = self::getCategories($pid);
        }

        $ids = array_column($categories, 'id');
        $applies = ExchangeApply::where('buyer_user_id', get_user_id())->get()->toArray();
        $exchangeIds = array_column($applies, 'exchange_id');

        if (count($exchangeIds) == 0) {
            return [];
        }

        $exchanges = Exchange::whereIn('id', $exchangeIds)->get()->toArray();
        $categoryIds = array_column($exchanges, 'category_id');

        $ids = array_intersect($ids, $categoryIds);
        if (count($ids) == 0) {
            return [];
        }

        return ExchangeCategory::select(['id', 'name', 'thumb', 'sort'])->whereIn('id', $ids)->get()->toArray();
    }

    public static function likeExchange($exchangeId)
    {
        if (!self::isLikeExchange($exchangeId)) {
            LikeService::like($exchangeId, Like::TYPE_EXCHANGE, function ($exchangeId, $type) {
                Exchange::where('id', $exchangeId)->increment('like_count', 1);
            });
        }
    }

    public static function isLikeExchange($exchangeId)
    {
        return LikeService::isLike($exchangeId, Like::TYPE_EXCHANGE);
    }

    public static function cancelLikeExchange($exchangeId)
    {
        LikeService::cancelLike($exchangeId, Like::TYPE_EXCHANGE, function ($exchangeId, $type) {
            Exchange::where('id', $exchangeId)->decrement('like_count', 1);
        });
    }

    public static function collectExchange($exchangeId)
    {
        UserCollectService::collect(UserCollect::EXCHANGE, $exchangeId, function($type, $id) {
            Exchange::where('id', $id)->increment('collect_count', 1);
        });
    }

    public static function cancelCollectExchange($exchangeId)
    {
        UserCollectService::uncollect(UserCollect::EXCHANGE, $exchangeId, function($type, $id) {
            Exchange::where('id', $id)->decrement('collect_count', 1);
        });
    }
}
